using System;
using System.Collections;
using System.Linq;
using System.Threading;
using UnityEngine;
using UnityEngine.Events;

namespace Life.UI.MVC
{
    public class UIWaiter : CustomYieldInstruction
    {
        public long BindingId { get; private set; } = 0;
        public override bool keepWaiting => !_completed;
        private bool _completed;
        
        public event System.Action OnCompleteEvent;
        
        public void SetComplete()
        {
            if (_completed)
            {
                throw new Exception("UIWaiter早已设置为完成,若要复用请先调用Reset()。");
            }
            _completed = true;
            BindingId = 0;
            OnCompleteEvent?.Invoke();
        }
        /// <summary>
        /// 清空完成状态和事件
        /// </summary>
        public override void Reset()
        {
            _completed = false;
            OnCompleteEvent = null;
        }
        /// <summary>
        /// 清空完成状态和事件
        /// </summary>
        /// <returns></returns>
        public UIWaiter ResetState()
        {
            Reset();
            return this;
        }
        /// <summary>
        /// 绑定或者获取一个弱引用对象，当UIWaiter完成时，当前waiter的所有弱引用将释放UIWaiter引用
        /// </summary>
        /// <returns></returns>
        public UIWaiterRef BindReference()
        {
            if (BindingId == 0)
            {
                BindingId = UIWaiterRef.GetId;
            }
            return UIWaiterRefCreator.Create.Invoke(BindingId,this);
        }
        /// <summary>
        /// 解除绑定
        /// </summary>
        public void Disbinding()
        {
            BindingId = 0;
        }
        
        /// <summary>
        /// 自动置空传入的引用 后再执行 UIWaiter SetComplete函数 ！！注意！！此操作会导致失去该对象的引用，请确保传入的引用确实需要置空再执行
        /// </summary>
        /// <param name="waiter"></param>
        [Obsolete("已弃用，请使用UIWaiterRef.Complete")]
        public static void SetCompleteOnce(ref UIWaiter waiter)
        {
            var temp = waiter;
            waiter = null;
            temp?.SetComplete();
        }
        public static implicit operator UIWaiter(System.Action action)
        {
            return new UIWaiter() { OnCompleteEvent = action };
        }
        public static implicit operator UIWaiter(UnityAction action)
        {
            return new UIWaiter() { OnCompleteEvent = action.Invoke };
        }
    }
    public class UIWaiter<T> : CustomYieldInstruction
    {
        public long BindingId { get; private set; } = 0;
        public override bool keepWaiting => !_completed;
        private bool _completed;
        
        public event System.Action<T> OnCompleteEvent;
        
        public T Value { get; private set; }
        public void SetComplete(T value)
        {
            if (_completed)
            {
                throw new Exception($"UIWaiter<{typeof(T).Name}>早已设置为完成,若要复用请先调用Reset()。");
            }
            Value = value;
            _completed = true;
            BindingId = 0;
            OnCompleteEvent?.Invoke(value);
        }
        /// <summary>
        /// 清空完成状态和事件
        /// </summary>
        public override void Reset()
        {
            Value = default;
            _completed = false;
            OnCompleteEvent = null;
        }
        /// <summary>
        /// 清空完成状态和事件
        /// </summary>
        /// <returns></returns>
        public UIWaiter<T> ResetState()
        {
            Reset();
            return this;
        }
        /// <summary>
        /// 绑定或者获取一个弱引用对象，当UIWaiter完成时，当前waiter的所有弱引用将释放UIWaiter引用
        /// </summary>
        /// <returns></returns>
        public UIWaiterRef<T> BindReference()
        {
            if (BindingId == 0)
            {
                BindingId = UIWaiterRef<T>.GetId;
            }
            return UIWaiterRefCreator<T>.Create(BindingId, this);
        }
        
        /// <summary>
        /// 解除绑定
        /// </summary>
        public void Disbinding()
        {
            BindingId = 0;
        }
        /// <summary>
        /// 自动置空传入的引用 后再执行 UIWaiter SetComplete函数 ！！注意！！此操作会导致失去该对象的引用，请确保传入的引用确实需要置空再执行
        /// </summary>
        /// <param name="waiter"></param>
        /// <param name="value"></param>
        /// <typeparam name="TValue"></typeparam>
        [Obsolete("已弃用，请使用UIWaiterRef<T>.Complete")]
        public static void SetCompleteOnce<TValue>(ref UIWaiter<TValue> waiter,TValue value)
        {
            var temp = waiter;
            waiter = null;
            temp?.SetComplete(value);
        }
        
        public static implicit operator UIWaiter<T>(System.Action<T> action)
        {
            return new UIWaiter<T>() { OnCompleteEvent = action };
        }
        public static implicit operator UIWaiter<T>(UnityAction<T> action)
        {
            return new UIWaiter<T>() { OnCompleteEvent = action.Invoke };
        }
    }
 
    internal static class UIWaiterRefCreator
    {
        public static long IdCounter = long.MinValue;
        public delegate UIWaiterRef CreateAction(long id,UIWaiter waiter);
        public static CreateAction Create;
    }
    internal static class UIWaiterRefCreator<T>
    {
        public delegate UIWaiterRef<T> CreateAction(long id,UIWaiter<T> waiter);
        public static CreateAction Create;
    }
    
    /// <summary>
    /// UIWaiter的弱引用器，请通过UIWaiter.BindingReference()或者UIWaiter实例隐式转换来获取实例
    /// </summary>
    public struct UIWaiterRef
    {
        static UIWaiterRef()
        {
            UIWaiterRefCreator.Create = Create;
        }
        private static UIWaiterRef Create(long id, UIWaiter reference)
        {
            return new UIWaiterRef()
            {
                WaiterId = id,
                _waiter = reference
            };
        }

        public static long GetId => (Interlocked.Increment(ref UIWaiterRefCreator.IdCounter) << 1) | 1;
        public long WaiterId { get; private set; }

        public bool IsAvailable => _waiter != null && _waiter.BindingId == WaiterId;
        UIWaiter _waiter;

        public UIWaiter Waiter
        {
            get
            {
                if(IsAvailable)
                    return _waiter;
                _waiter = null;
                return null;
            }
        }
        /// <summary>
        /// 设置完成 不安全检查
        /// </summary>
        /// <exception cref="Exception"></exception>
        public void SetComplete()
        {
            if (!IsAvailable)
            {
                throw new Exception("当前UIWaiterRef找不到绑定的UIWaiter，已失效。");
            }
            var temp = _waiter;
            _waiter = null;
            temp.SetComplete();
        }
        /// <summary>
        /// 设置完成 安全设置
        /// </summary>
        public void SafeComplete()
        {
            if (IsAvailable)
            {
                var temp = _waiter;
                _waiter = null;
                temp.SetComplete();
            }
        }
        public static implicit operator UIWaiterRef(UIWaiter waiter)
        {
            return waiter.BindReference();
        }
    }
    /// <summary>
    /// UIWaiter[T]的弱引用器，请通过UIWaiter[T].BindingReference()或者UIWaiter实例隐式转换来获取实例
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public struct UIWaiterRef<T>
    {
        static UIWaiterRef()
        {
            UIWaiterRefCreator<T>.Create = Create;
        }
        private static UIWaiterRef<T> Create(long id, UIWaiter<T> reference)
        {
            return new UIWaiterRef<T>()
            {
                WaiterId = id,
                _waiter = reference
            };
        }
        public static long GetId => (Interlocked.Increment(ref UIWaiterRefCreator.IdCounter) << 1) | 1;
        public long WaiterId { get; private set; }

        public bool IsAvailable => _waiter != null && _waiter.BindingId == WaiterId;
        UIWaiter<T> _waiter;

        public UIWaiter<T> Waiter
        {
            get
            {
                if(IsAvailable)
                    return _waiter;
                _waiter = null;
                return null;
            }
        }
        /// <summary>
        /// 设置完成 不安全检查 完成后将自动解绑
        /// </summary>
        /// <param name="value"></param>
        /// <exception cref="Exception"></exception>
        public void SetComplete(T value)
        {
            if (!IsAvailable)
            {
                throw new Exception($"当前UIWaiterRef<{typeof(T).Name}>找不到绑定的UIWaiter，已失效。");
            }
            var temp = _waiter;
            _waiter = null;
            temp.SetComplete(value);
        }
        /// <summary>
        /// 设置完成 安全设置 完成后将自动解绑
        /// </summary>
        public void SafeComplete(T value)
        {
            if (IsAvailable)
            {
                var temp = _waiter;
                _waiter = null;
                temp.SetComplete(value);
            }
        }
        public static implicit operator UIWaiterRef<T>(UIWaiter<T> waiter)
        {
            return waiter.BindReference();
        }
    }

    public class UIWaiterGroup : CustomYieldInstruction
    {
        private CustomYieldInstruction[] _customYieldInstructions;

        public UIWaiterGroup WaitAll(params CustomYieldInstruction[] customYieldInstructions)
        {
            _customYieldInstructions = customYieldInstructions;
            UIManager.CoroutineStart(WaitAllComplete());
            return this;
        }
        
        public UIWaiterGroup WaitAll<T>(UIWaiterPool.UIWaiter<T>[] customYieldInstructions)
        {
            _customYieldInstructions = new CustomYieldInstruction[customYieldInstructions.Length];
            for (var i = 0; i < customYieldInstructions.Length; i++)
            {
                _customYieldInstructions[i] = customYieldInstructions[i];
            }
            UIManager.CoroutineStart(WaitAllComplete());
            return this;
        }
        
        public UIWaiterGroup WaitAll<T>(UIWaiter<T>[] customYieldInstructions)
        {
            _customYieldInstructions = new CustomYieldInstruction[customYieldInstructions.Length];
            for (var i = 0; i < customYieldInstructions.Length; i++)
            {
                _customYieldInstructions[i] = customYieldInstructions[i];
            }
            UIManager.CoroutineStart(WaitAllComplete());
            return this;
        }
        public UIWaiterGroup WaitAll(UIWaiterPool.UIWaiter[] customYieldInstructions)
        {
            _customYieldInstructions = new CustomYieldInstruction[customYieldInstructions.Length];
            for (var i = 0; i < customYieldInstructions.Length; i++)
            {
                _customYieldInstructions[i] = customYieldInstructions[i];
            }
            UIManager.CoroutineStart(WaitAllComplete());
            return this;
        }
        public UIWaiterGroup WaitAll(UIWaiter[] customYieldInstructions)
        {
            _customYieldInstructions = new CustomYieldInstruction[customYieldInstructions.Length];
            for (var i = 0; i < customYieldInstructions.Length; i++)
            {
                _customYieldInstructions[i] = customYieldInstructions[i];
            }
            UIManager.CoroutineStart(WaitAllComplete());
            return this;
        }
        
        IEnumerator WaitAllComplete()
        {
            if (_customYieldInstructions != null)
                yield return new WaitUntil(() => _customYieldInstructions.All(w => !w.keepWaiting));
            _completed = true;
            OnCompleteEvent?.Invoke();
        }
        
        public override bool keepWaiting => !_completed;
        private bool _completed;
        
        public event System.Action OnCompleteEvent;
        
        public static implicit operator UIWaiterGroup(System.Action action)
        {
            return new UIWaiterGroup() { OnCompleteEvent = action };
        }
        public static implicit operator UIWaiterGroup(UnityAction action)
        {
            return new UIWaiterGroup() { OnCompleteEvent = action.Invoke };
        }
        
        /// <summary>
        /// 清空完成状态和事件
        /// </summary>
        public override void Reset()
        {
            _completed = false;
            _customYieldInstructions = null;
            OnCompleteEvent = null;
        }
    }
}